﻿// MyProject.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//公众号：程序员速成 ，内含一辈子都让你感激自己的优质视频教程，欢迎关注

#include <iostream>
#include <list>


#ifdef _DEBUG   //只在Debug（调试）模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{	
	//药品父类
	class Medicine
	{
	public:
		virtual string getMdcName() = 0; //药品名称
		virtual float getPrice() = 0; //药品总价格，单位：元

		virtual ~Medicine() {} //做父类应该有个虚析构函数
	};
	
	//药品：阿司匹林肠溶片
	class M_asplcrp :public Medicine
	{
	public:
		virtual string getMdcName()
		{
			return "阿司匹林肠溶片";
		}
		virtual float getPrice()
		{
			return 46.8f; //药品总价
		}
	};

	//药品：氟伐他汀钠缓释片
	class M_fftdnhsp :public Medicine
	{
	public:
		virtual string getMdcName()
		{
			return "氟伐他汀钠缓释片";
		}
		virtual float getPrice()
		{
			return 111.3f; //药品总价
		}
	};

	//药品：黛力新
	class M_dlx :public Medicine
	{
	public:
		virtual string getMdcName()
		{
			return "黛力新";
		}
		virtual float getPrice()
		{
			return 122.0f; //药品总价
		}
	};
	/*
	//----------------
	//针对药品的处理相关类
	class MedicineProc
	{
	public: 
		//增加药品到药品列表中
		void addMedicine(Medicine* p_mdc)
		{
			m_mdclist.push_back(p_mdc);
		}

		//针对费用缴纳和取药所做的处理动作
		void procAction(string strvisitor) //strvisitor代表拿到了药品单的人，不同的人拿到药品单所要做的处理不同
		{
			if (strvisitor == "收费人员") //收费人员要根据药品单向我（患者）收取费用
			{
				float totalcost = 0.0f; //总费用
				for (auto iter = m_mdclist.begin(); iter != m_mdclist.end(); ++iter)
				{
					float tmpprice = (*iter)->getPrice();
					cout << "收费人员累计药品\"" << (*iter)->getMdcName() << "\"的价格：" << tmpprice << endl;
					totalcost += tmpprice;
				}//end for
				cout << "所有药品的总价为：" << totalcost << ",收费人员收取了我的费用!" << endl;
			}
			else if (strvisitor == "取药人员") //取药人员要根据药品单为我拿药
			{
				for (auto iter = m_mdclist.begin(); iter != m_mdclist.end(); ++iter)
				{
					cout << "取药人员将药品\"" << (*iter)->getMdcName() << "\"拿给了我！" << endl;
				}
			}
			else if (strvisitor == "营养师")
			{
				cout << "营养师建议：主食中多搭配粗粮，适当食用肉类！" << endl;
			}
			else if (strvisitor == "健身教练")
			{
				cout << "健身教练建议：多做有氧运动比如慢跑（35分钟即可），慢跑前后要热身，忌焦虑，忌熬夜，以22:30之前卧床休息为宜！" << endl;
			}
		}

	private:
		list <Medicine*> m_mdclist; //药品列表，记录着药品单上的所有药品。
	};
	*/

	//-------------------
	//访问者父类
	class Visitor
	{
	public:
		virtual ~Visitor() {} //做父类时析构函数应该为虚函数

		virtual void Visit_elm_asplcrp(M_asplcrp* pelem) = 0; //访问元素：阿司匹林肠溶片
		virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem) = 0; //访问元素：氟伐他汀钠缓释片
		virtual void Visit_elm_dlx(M_dlx* pelem) = 0; //访问元素：黛力新

		//virtual void Visit(M_asplcrp* pelem) = 0; //访问元素：阿司匹林肠溶片
		//virtual void Visit(M_fftdnhsp* pelem) = 0; //访问元素：氟伐他汀钠缓释片
		//virtual void Visit(M_dlx* pelem) = 0; //访问元素：黛力新
	};

	//收费人员访问者子类
	class Visitor_SFRY : public Visitor
	{
		virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
		{
			float tmpprice = pelem->getPrice();
			cout << "收费人员累计药品\"" << pelem->getMdcName() << "\"的价格：" << tmpprice << endl;
			m_totalcost += tmpprice;
		}
		virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
		{
			float tmpprice = pelem->getPrice();
			cout << "收费人员累计药品\"" << pelem->getMdcName() << "\"的价格：" << tmpprice << endl;
			m_totalcost += tmpprice;
		}
		virtual void Visit_elm_dlx(M_dlx* pelem)
		{
			float tmpprice = pelem->getPrice();
			cout << "收费人员累计药品\"" << pelem->getMdcName() << "\"的价格：" << tmpprice << endl;
			m_totalcost += tmpprice;
		}

		//返回总费用
		float getTotalCost()
		{
			return m_totalcost;
		}

	private:
		float m_totalcost = 0.0f; //总费用
	};

	//取药人员访问者子类
	class Visitor_QYRY : public Visitor
	{
		virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
		{
			cout << "取药人员将药品\"" << pelem->getMdcName() << "\"拿给了我！" << endl;
		}
		virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
		{
			cout << "取药人员将药品\"" << pelem->getMdcName() << "\"拿给了我！" << endl;
		}
		virtual void Visit_elm_dlx(M_dlx* pelem)
		{
			cout << "取药人员将药品\"" << pelem->getMdcName() << "\"拿给了我！" << endl;
		}
	};

}

int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口
	
	
	//第20章 访问者（Visitor）模式：访问器模式，行为型模式。
	//（1）一个具体范例的逐渐演化
	//阿司匹林肠溶片：改善血液流通，预防血栓形成，血栓形成就产生阻塞，人就会直接面临危险；
	//氟伐他汀钠缓释片：降血脂。因为血脂高意味着血流慢，营养无法运输到身体各部位，还很可能引发心脑血管疾病；
	//黛力新：医生说我的心脏没有器质性病变，是神经出现了紊乱，出现的症状是因为神经的误报，因此开此药治疗植物神经功能紊乱以及身心疾病伴有的焦虑症状；
	//缴费，取药。

	//访问者模式：包含 访问者（收费人员、取药人员、营养师、健身教练），被访问者（元素）（药品单中的三种药品） 两个重要角色
	//访问：a)串门。b)查看一个东西

	/*
	_nmsp1::Medicine* pm1 = new _nmsp1::M_asplcrp();
	_nmsp1::Medicine* pm2 = new _nmsp1::M_fftdnhsp();
	_nmsp1::Medicine* pm3 = new _nmsp1::M_dlx();

	_nmsp1::MedicineProc mdcprocobj;
	mdcprocobj.addMedicine(pm1);
	mdcprocobj.addMedicine(pm2);
	mdcprocobj.addMedicine(pm3);
	mdcprocobj.procAction("收费人员");
	mdcprocobj.procAction("取药人员");


	//释放资源
	delete pm1;
	delete pm2;
	delete pm3;*/




	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件


/*
	阿司匹林肠溶片：改善血液流通，预防血栓形成，血栓形成就产生阻塞，人就会直接面临危险；
	氟伐他汀钠缓释片：降血脂。因为血脂高意味着血流慢，营养无法运输到身体各部位，还很可能引发心脑血管疾病；
	黛力新：医生说我的心脏没有器质性病变，是神经出现了紊乱，出现的症状是因为神经的误报，因此开此药治疗植物神经功能紊乱以及身心疾病伴有的焦虑症状；
*/